#pragma code_seg("C853")
#pragma data_seg("D853")
#pragma bss_seg("B853")
#pragma const_seg("K853")
#pragma comment(linker, "/merge:D853=853")
#pragma comment(linker, "/merge:C853=853")
#pragma comment(linker, "/merge:B853=853")
#pragma comment(linker, "/merge:K853=853")
/*

Dream World
SemiCom, 2000

PCB Layout
----------

|-------------------------------------------------|
|    M6295  ROM5    62256   ACTEL           ROM10 |
|VOL M6295  ROM6    62256   A40MX04               |
|    PAL  PAL       32MHz                         |
| 62256  62256              PAL                   |
| ROM1 ROM3       68EC020   PAL    PAL            |
| ROM2 ROM4                 PAL    PAL            |
|J 62256 62256              PAL                   |
|A                          PAL    27MHz          |
|M                                 PAL            |
|M                         ACTEL    M5M44260      |
|A             6116        A40MX04  M5M44260      |
|              6116                               |
|                          PAL                    |
|              6264        PAL                    |
|              6264                               |
| DSW1                      ROM11                 |
|        8752        ROM7   ROM9                  |
| DSW2               ROM8                         |
|-------------------------------------------------|
Notes:
      68020 @ 16.0MHz [32/2]
      M6295 (both) @ 1.0MHz [32/32]. pin 7 LOW
      8752 @ 16.0MHz [32/2]
      HSync @ 15.2kHz
      VSync @ 58Hz

*/

#include "driver.h"
#include "cpu/m68000/m68000.h"

#define MASTER_CLOCK 32000000

static unsigned int *spriteram32;

static UINT32*dreamwld_bg_videoram;
static UINT32*dreamwld_bg2_videoram;
static UINT32*dreamwld_bg_scroll;
static int dreamwld_tilebank[2], dreamwld_tilebankold[2];

static struct tilemap *dreamwld_bg_tilemap;
static struct tilemap *dreamwld_bg2_tilemap;

static void draw_sprites(struct mame_bitmap *bitmap)
{
	UINT32 *source = spriteram32;
	UINT32 *finish = spriteram32 + 0x1000/4;
	UINT16 *redirect = (UINT16 *)memory_region(REGION_GFX3);

	while( source<finish )
	{
		int xpos, ypos, tileno;
		int xsize, ysize, xinc;
		int xct, yct;
		int xflip;
		int colour;

		xpos =  (source[0]&0x000001ff) >> 0;
		ypos =  (source[0]&0x01ff0000) >> 16;
		xsize = (source[0]&0x00000e00) >> 9;
		ysize = (source[0]&0x0e000000) >> 25;


		tileno = (source[1]&0x0000ffff) >>0;
		colour = (source[1]&0x3f000000) >>24;
		xflip  = (source[1]&0x40000000);

		xinc = 16;

		if (xflip)
		{
			xinc = -16;
			xpos+=16*xsize;
		}

		ysize++; xsize++; // size 0 = 1 tile

		xpos -=16;

		for (yct=0;yct<ysize;yct++)
		{
			for (xct=0;xct<xsize;xct++)
			{
				drawgfx(bitmap,Machine->gfx[0],redirect[tileno],colour,xflip,0,xpos+xct*xinc,ypos+yct*16,&Machine->visible_area,TRANSPARENCY_PEN,0);
				drawgfx(bitmap,Machine->gfx[0],redirect[tileno],colour,xflip,0,(xpos+xct*xinc)-0x200,ypos+yct*16,&Machine->visible_area,TRANSPARENCY_PEN,0);
				drawgfx(bitmap,Machine->gfx[0],redirect[tileno],colour,xflip,0,(xpos+xct*xinc)-0x200,(ypos+yct*16)-0x200,&Machine->visible_area,TRANSPARENCY_PEN,0);
				drawgfx(bitmap,Machine->gfx[0],redirect[tileno],colour,xflip,0,xpos+xct*xinc,(ypos+yct*16)-0x200,&Machine->visible_area,TRANSPARENCY_PEN,0);

				tileno++;
			}
		}

		source+=2;
	}
}

static WRITE32_HANDLER( dreamwld_bg_videoram_w )
{
	COMBINE_DATA(&dreamwld_bg_videoram[offset]);
	tilemap_mark_tile_dirty(dreamwld_bg_tilemap,offset*2);
	tilemap_mark_tile_dirty(dreamwld_bg_tilemap,offset*2+1);

}

static void get_dreamwld_bg_tile_info(int tile_index) //TILE_GET_INFO( get_dreamwld_bg_tile_info )
{
	int tileno,colour;
	tileno = (tile_index&1)?(dreamwld_bg_videoram[tile_index>>1]&0xffff):((dreamwld_bg_videoram[tile_index>>1]>>16)&0xffff);
	colour = tileno >> 13;
	tileno &=0x1fff;
	SET_TILE_INFO(1,tileno+dreamwld_tilebank[0]*0x2000,0x80+colour,0);
}


static WRITE32_HANDLER( dreamwld_bg2_videoram_w )
{
	COMBINE_DATA(&dreamwld_bg2_videoram[offset]);
	tilemap_mark_tile_dirty(dreamwld_bg2_tilemap,offset*2);
	tilemap_mark_tile_dirty(dreamwld_bg2_tilemap,offset*2+1);
}

static void get_dreamwld_bg2_tile_info(int tile_index) //TILE_GET_INFO( get_dreamwld_bg2_tile_info )
{
	UINT16 tileno,colour;
	tileno = (tile_index&1)?(dreamwld_bg2_videoram[tile_index>>1]&0xffff):((dreamwld_bg2_videoram[tile_index>>1]>>16)&0xffff);
	colour = tileno >> 13;
	tileno &=0x1fff;
	SET_TILE_INFO(1,tileno+dreamwld_tilebank[1]*0x2000,0xc0+colour,0);
}

static VIDEO_START( dreamwld )
{
	dreamwld_bg_tilemap = tilemap_create(get_dreamwld_bg_tile_info, tilemap_scan_rows, TILEMAP_OPAQUE, 16, 16, 64,32);
	dreamwld_bg2_tilemap = tilemap_create(get_dreamwld_bg2_tile_info, tilemap_scan_rows, TILEMAP_TRANSPARENT, 16, 16, 64,32);
	tilemap_set_transparent_pen(dreamwld_bg2_tilemap,0);
	dreamwld_tilebankold[0] = dreamwld_tilebankold[1] = -1;
	dreamwld_tilebank[0] = dreamwld_tilebank[1] = 0;

	return 0;
}

static VIDEO_UPDATE( dreamwld )
{
	tilemap_set_scrolly( dreamwld_bg_tilemap,0, dreamwld_bg_scroll[(0x400/4)]+32 );
	tilemap_set_scrolly( dreamwld_bg2_tilemap,0, dreamwld_bg_scroll[(0x400/4)+2]+32 );
	tilemap_set_scrollx( dreamwld_bg_tilemap,0, dreamwld_bg_scroll[(0x400/4)+1]+3 );
	tilemap_set_scrollx( dreamwld_bg2_tilemap,0, dreamwld_bg_scroll[(0x400/4)+3]+5 );

	dreamwld_tilebank[0] = (dreamwld_bg_scroll[(0x400/4)+4]>>6)&1;
	dreamwld_tilebank[1] = (dreamwld_bg_scroll[(0x400/4)+5]>>6)&1;

	if (dreamwld_tilebank[0] != dreamwld_tilebankold[0])
	{
		dreamwld_tilebankold[0] = dreamwld_tilebank[0];
		tilemap_mark_all_tiles_dirty (dreamwld_bg_tilemap);
	}

	if (dreamwld_tilebank[1] != dreamwld_tilebankold[1])
	{
		dreamwld_tilebankold[1] = dreamwld_tilebank[1];
		tilemap_mark_all_tiles_dirty (dreamwld_bg2_tilemap);
	}

	tilemap_draw(bitmap,cliprect,dreamwld_bg_tilemap,0,0);
	tilemap_draw(bitmap,cliprect,dreamwld_bg2_tilemap,0,0);

	draw_sprites(bitmap);
}

static READ32_HANDLER( dreamwld_protdata_r )
{
	static int protindex = 0;
	UINT8 *protdata    = memory_region(REGION_USER1);
	size_t  protsize = memory_region_length(REGION_USER1);
	UINT8 dat = protdata[(protindex++)%protsize];
	return dat<<24;
}


static WRITE32_HANDLER( dreamwld_palette_w )
{
	UINT16 dat;
	int color;

	COMBINE_DATA(&paletteram32[offset]);
	color = offset * 2;

#define pal5bit(n)	((((n) & 0x1f) << 3) | (((n) & 0x1f) >> 2))

	dat = paletteram32[offset] & 0x7fff;
	palette_set_color(color + 1, pal5bit(dat >> 10), pal5bit(dat >> 5), pal5bit(dat >> 0));

	dat = (paletteram32[offset] >> 16) & 0x7fff;
	palette_set_color(color, pal5bit(dat >> 10), pal5bit(dat >> 5), pal5bit(dat >> 0));
#undef pal5bit
}

static void dreamwld_oki_setbank(UINT8 chip, UINT8 bank )
{
	UINT8 *sound = memory_region(chip ? REGION_SOUND1 : REGION_SOUND2);

	memcpy(sound+0x30000, sound+0xb0000+0x10000*bank, 0x10000);
}

static WRITE32_HANDLER( dreamwld_6295_0_bank_w )
{
	if (1) //ACCESSING_BITS_0_7)
	{
		dreamwld_oki_setbank(0,data&0x3);
	}
	else
	{
	//	logerror("OKI0: unk bank write %x mem_mask %8x\n", data, mem_mask);
	}
}

static WRITE32_HANDLER( dreamwld_6295_1_bank_w )
{
	if (1) //ACCESSING_BITS_0_7)
	{
		dreamwld_oki_setbank(1,data&0x3);
	}
	else
	{
	//	logerror("OKI1: unk bank write %x mem_mask %8x\n", data, mem_mask);
	}
}

static READ32_HANDLER(dreamwld_6295_0_r)
{
	return OKIM6295_status_0_r(0) << 24;
}

static WRITE32_HANDLER(dreamwld_6295_0_w)
{
	if (1) // msb
	{
		OKIM6295_data_0_w(0, data >> 24);
	}
}

static READ32_HANDLER(dreamwld_6295_1_r)
{
	return OKIM6295_status_1_r(0) << 24;
}

static WRITE32_HANDLER(dreamwld_6295_1_w)
{
	if (1) // msb
	{
		OKIM6295_data_1_w(0, data >> 24);
	}
}

static READ32_HANDLER(inputs_32_r)
{
	return (readinputport(1) << 16) | readinputport(0);
}

static READ32_HANDLER(dips_32_r)
{
	return (readinputport(2) << 16) | readinputport(2);
}

static ADDRESS_MAP_START( dreamwld_readmem, ADDRESS_SPACE_PROGRAM, 32 )
	AM_RANGE(0x000000, 0x0fffff) AM_READ(MRA32_ROM)
	AM_RANGE(0x400000, 0x401fff) AM_READ(MRA32_RAM)
	AM_RANGE(0x600000, 0x601fff) AM_READ(MRA32_RAM)
	AM_RANGE(0x800000, 0x801fff) AM_READ(MRA32_RAM)
	AM_RANGE(0x802000, 0x803fff) AM_READ(MRA32_RAM)
	AM_RANGE(0x804000, 0x805fff) AM_READ(MRA32_RAM)
	AM_RANGE(0xc00018, 0xc0001b) AM_READ(dreamwld_6295_0_r)
	AM_RANGE(0xc00028, 0xc0002b) AM_READ(dreamwld_6295_1_r)
	AM_RANGE(0xc00030, 0xc00033) AM_READ(dreamwld_protdata_r)
	AM_RANGE(0xc00000, 0xc00003) AM_READ(inputs_32_r)
	AM_RANGE(0xc00004, 0xc00007) AM_READ(dips_32_r)
	AM_RANGE(0xfe0000, 0xffffff) AM_READ(MRA32_RAM)
ADDRESS_MAP_END

static ADDRESS_MAP_START( dreamwld_writemem, ADDRESS_SPACE_PROGRAM, 32 )
	AM_RANGE(0x000000, 0x0fffff) AM_WRITE(MWA32_ROM)
	AM_RANGE(0x400000, 0x401fff) AM_WRITE(MWA32_RAM) AM_BASE( &spriteram32 )
	AM_RANGE(0x600000, 0x601fff) AM_WRITE(dreamwld_palette_w) AM_BASE(&paletteram32) 
	AM_RANGE(0x800000, 0x801fff) AM_WRITE(dreamwld_bg_videoram_w )  AM_BASE( &dreamwld_bg_videoram )
	AM_RANGE(0x802000, 0x803fff) AM_WRITE(dreamwld_bg2_videoram_w ) AM_BASE( &dreamwld_bg2_videoram )
	AM_RANGE(0x804000, 0x805fff) AM_WRITE(MWA32_RAM)                AM_BASE( &dreamwld_bg_scroll )  // scroll regs etc.
	AM_RANGE(0xc0000c, 0xc0000f) AM_WRITE(dreamwld_6295_0_bank_w) // sfx
	AM_RANGE(0xc00018, 0xc0001b) AM_WRITE(dreamwld_6295_0_w)
	AM_RANGE(0xc0002c, 0xc0002f) AM_WRITE(dreamwld_6295_1_bank_w) // sfx
	AM_RANGE(0xc00028, 0xc0002b) AM_WRITE(dreamwld_6295_1_w)
	AM_RANGE(0xfe0000, 0xffffff) AM_WRITE( MWA32_RAM )
ADDRESS_MAP_END


static INPUT_PORTS_START( dreamwld )
	// mame can't handle 32-bit inputs, so we set them as 16-bit and assemble them later
	PORT_START
	PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_BIT( 0xfffc, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START
	PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_START2 )
	PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON3 | IPF_PLAYER2 ) /* "Book" (when you get one of them) */
	PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON2 | IPF_PLAYER2 ) /* "Jump" */
	PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER2 ) /* "Dig" */
	PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT | IPF_PLAYER2 ) 
	PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT | IPF_PLAYER2 )
	PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN | IPF_PLAYER2 ) 
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_UP | IPF_PLAYER2 )
	PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 | IPF_PLAYER1 ) /* "Book" (when you get one of them) */
	PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 | IPF_PLAYER1 ) /* "Jump" */
	PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER1 ) /* "Dig" */
	PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT | IPF_PLAYER1 ) 
	PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT | IPF_PLAYER1 )
	PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN | IPF_PLAYER1 ) 
	PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP | IPF_PLAYER1 ) 

	PORT_START		/* 16bit */
	PORT_DIPNAME( 0x0003, 0x0003, DEF_STR( Lives ) ) 
	PORT_DIPSETTING(      0x0002, "2" )
	PORT_DIPSETTING(      0x0003, "3" )
	PORT_DIPSETTING(      0x0001, "4" )
	PORT_DIPSETTING(      0x0000, "5" )
	PORT_DIPNAME( 0x007c, 0x007c, DEF_STR( Unknown ) )
	PORT_DIPSETTING(      0x007c, DEF_STR( Off ) )
	PORT_DIPSETTING(      0x0000, DEF_STR( On ) )
	PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Free_Play ) )  
	PORT_DIPSETTING(      0x0080, DEF_STR( Off ) )
	PORT_DIPSETTING(      0x0000, DEF_STR( On ) )
	PORT_DIPNAME( 0x0100, 0x0100, DEF_STR( Unknown ) )
	PORT_DIPSETTING(      0x0100, DEF_STR( Off ) )
	PORT_DIPSETTING(      0x0000, DEF_STR( On ) )
	PORT_DIPNAME( 0x0e00, 0x0e00, DEF_STR( Coinage ) )
	PORT_DIPSETTING(      0x0000, DEF_STR( 5C_1C ) )
	PORT_DIPSETTING(      0x0200, DEF_STR( 4C_1C ) )
	PORT_DIPSETTING(      0x0400, DEF_STR( 3C_1C ) )
	PORT_DIPSETTING(      0x0600, DEF_STR( 2C_1C ) )
	PORT_DIPSETTING(      0x0e00, DEF_STR( 1C_1C ) )
	PORT_DIPSETTING(      0x0a00, DEF_STR( 2C_3C ) )
	PORT_DIPSETTING(      0x0c00, DEF_STR( 1C_2C ) )
	PORT_DIPSETTING(      0x0800, DEF_STR( 1C_3C ) )
	PORT_DIPNAME( 0x7000, 0x7000, DEF_STR( Unknown ) )
	PORT_DIPSETTING(      0x7000, DEF_STR( Off ) )
	PORT_DIPSETTING(      0x0000, DEF_STR( On ) )
	PORT_SERVICE( 0x8000, IP_ACTIVE_LOW )
INPUT_PORTS_END

static struct GfxLayout tiles16x16_layout =
{
	16,16,
	RGN_FRAC(1,1),
	4,
	{ 0, 1, 2, 3 },
	{ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60 },
	{ 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64,8*64,9*64,10*64,11*64,12*64,13*64,14*64,15*64 },
	16*64
};

static struct GfxDecodeInfo gfxdecodeinfo[] =
{
	{ REGION_GFX1, 0, &tiles16x16_layout,  0x0000, 256 },
	{ REGION_GFX2, 0, &tiles16x16_layout,  0x0000, 256 },
	{ -1 }
};

static struct OKIM6295interface m6295_interface =
{
	2,  /* 2 chips */
	{ MASTER_CLOCK/32/165, MASTER_CLOCK/32/165 }, /* unknown, but sounds good */
	{ REGION_SOUND1, REGION_SOUND2 },
	{ 50,50 }
};

static MACHINE_DRIVER_START( dreamwld )

	/* basic machine hardware */
	MDRV_CPU_ADD(M68EC020, MASTER_CLOCK/2)
	MDRV_CPU_PROGRAM_MAP(dreamwld_readmem,dreamwld_writemem)
	MDRV_CPU_VBLANK_INT(irq4_line_hold,1)

	MDRV_FRAMES_PER_SECOND(58)
	MDRV_VBLANK_DURATION(TIME_IN_USEC(0))

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER )
	MDRV_SCREEN_SIZE(64*8, 32*8)
	MDRV_VISIBLE_AREA(0, 304-1, 0, 224-1)
	MDRV_GFXDECODE(gfxdecodeinfo)
	MDRV_PALETTE_LENGTH(0x1000)

	MDRV_VIDEO_START(dreamwld)
	MDRV_VIDEO_UPDATE(dreamwld)

	/* sound hardware */
	MDRV_SOUND_ATTRIBUTES(SOUND_SUPPORTS_STEREO)
	MDRV_SOUND_ADD(OKIM6295, m6295_interface)
MACHINE_DRIVER_END


ROM_START( dreamwld )
	ROM_REGION( 0x200000, REGION_CPU1, 0 )
	ROM_LOAD32_BYTE( "1.bin", 0x000002, 0x040000, CRC(35c94ee5) SHA1(3440a65a807622b619c97bc2a88fd7d875c26f66) )
	ROM_LOAD32_BYTE( "2.bin", 0x000003, 0x040000, CRC(5409e7fc) SHA1(2f94a6a8e4c94b36b43f0b94d58525f594339a9d) )
	ROM_LOAD32_BYTE( "3.bin", 0x000000, 0x040000, CRC(e8f7ae78) SHA1(cfd393cec6dec967c82e1131547b7e7fdc5d814f) )
	ROM_LOAD32_BYTE( "4.bin", 0x000001, 0x040000, CRC(3ef5d51b) SHA1(82a00b4ff7155f6d5553870dfd510fed9469d9b5) )

	ROM_REGION( 0x10000, REGION_CPU2, 0 ) /* 87C52 MCU Code */
	//ROM_LOAD( "87c52.mcu", 0x00000, 0x10000 , NO_DUMP ) /* can't be dumped. */

	ROM_REGION( 0x6c9, REGION_USER1, 0 ) /* Protection data  */
	/* The MCU supplies this data.
      The 68k reads it through a port, taking the size and destination write address from the level 1
      and level 2 irq positions in the 68k vector table (there is code to check that they haven't been
      modofied!)  It then decodes the data using the rom checksum previously calculated and puts it in
      ram.  The interrupt vectors point at the code placed in RAM. */
	ROM_LOAD( "protdata.bin", 0x000, 0x6c9 ,  CRC(f284b2fd) SHA1(9e8096c8aa8a288683f002311b38787b120748d1) ) /* extracted */

	ROM_REGION( 0x100000, REGION_SOUND1, 0 ) /* OKI Samples - 1st chip*/
	ROM_LOAD( "5.bin", 0x000000, 0x80000, CRC(9689570a) SHA1(4414233da8f46214ca7e9022df70953922a63aa4) )
	ROM_RELOAD(0x80000,0x80000) // for the banks

	ROM_REGION( 0x100000, REGION_SOUND2, 0 ) /* OKI Samples - 2nd chip*/
	ROM_LOAD( "6.bin", 0x000000, 0x80000, CRC(c8b91f30) SHA1(706004ca56d0a74bc7a3dfd73a21cdc09eb90f05) )
	ROM_RELOAD(0x80000,0x80000) // for the banks

	ROM_REGION( 0x400000, REGION_GFX1, 0 ) /* Sprite Tiles - decoded */
	ROM_LOAD( "9.bin", 0x000000, 0x200000, CRC(fa84e3af) SHA1(5978737d348fd382f4ec004d29870656c864d137) )

	ROM_REGION( 0x200000, REGION_GFX2, 0 ) /* BG Tiles - decoded */
	ROM_LOAD( "10.bin",0x000000, 0x200000, CRC(3553e4f5) SHA1(c335494f4a12a01a88e7cd578cae922954303cfd) )

	ROM_REGION( 0x040000, REGION_GFX3, 0 ) /* Sprite Code Lookup ... */
	ROM_LOAD16_BYTE( "8.bin", 0x000000, 0x020000, CRC(8d570df6) SHA1(e53e4b099c64eca11d027e0083caa101fcd99959) )
	ROM_LOAD16_BYTE( "7.bin", 0x000001, 0x020000, CRC(a68bf35f) SHA1(f48540a5415a7d9723ca6e7e03cab039751dce17) )

	ROM_REGION( 0x10000, REGION_GFX4, 0 ) /* ???? - not decoded seems to be in blocks of 0x41 bytes.. */
	ROM_LOAD( "11.bin", 0x000000, 0x10000, CRC(0da8db45) SHA1(7d5bd71c5b0b28ff74c732edd7c662f46f2ab25b) )
ROM_END

GAME( 2000, dreamwld, 0,        dreamwld, dreamwld, 0, ROT0,  "Other", "Dream World" )

#pragma code_seg()
#pragma data_seg()
#pragma bss_seg()
#pragma const_seg()